
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GLES/gl.h> /* For NDK*/
#include <android/log.h>
#include "utils.h"
#include "jade.h"



jade_mesh_t *
jade_mesh_create () {
//jade_mesh_create (GLfloat *vertices, GLfloat *normals, GLfloat *uvs, GLint triangle_num) {

    jade_mesh_t *mesh;

    mesh = (jade_mesh_t*)malloc (sizeof (jade_mesh_t));
    if (mesh == NULL)
        return NULL;

    mesh->m_vertices = NULL;
    mesh->m_normals = NULL;
    mesh->m_uvs = NULL;
    mesh->m_colors = NULL;
    mesh->m_indices = NULL;
    mesh->m_position = NULL;
    mesh->m_rotate = NULL;
    mesh->m_scale = NULL;
    mesh->m_textureId = -1;
    mesh->m_triangleNums = 0;
    mesh->m_enabled = GL_FALSE;
    mesh->m_texureoffset = NULL;

    return mesh;
}

void jade_mesh_destroy (jade_mesh_t *mesh) {

    if (mesh == NULL) {
        return;
    }

    if (mesh->m_vertices != NULL) {
        FREEANDNULL (mesh->m_vertices);
    }

    if (mesh->m_normals != NULL) {

        FREEANDNULL (mesh->m_normals);
    }


    if (mesh->m_uvs != NULL) {

        FREEANDNULL (mesh->m_uvs);
    }


    if (mesh->m_colors != NULL) {

        FREEANDNULL (mesh->m_colors);
    }

    if (mesh->m_indices != NULL) {

        FREEANDNULL (mesh->m_indices);
    }

    if (mesh->m_position != NULL) {

        FREEANDNULL (mesh->m_position);
    }

    if (mesh->m_rotate != NULL) {

        FREEANDNULL (mesh->m_rotate);
    }


    if (mesh->m_texureoffset != NULL) {

        FREEANDNULL (mesh->m_texureoffset); 
    }


    if (mesh->m_scale != NULL) {

        FREEANDNULL (mesh->m_scale);
    }


    if (mesh != NULL)
        FREEANDNULL (mesh);



    return;
}


void jade_mesh_set_triangle_num (jade_mesh_t *mesh, GLint num) {

     mesh->m_triangleNums = num;
}

void jade_mesh_set_vertices (jade_mesh_t *mesh, GLfloat *vertices, int size) {

    FREEANDNULL(mesh->m_vertices);
    mesh->m_vertices = (GLfloat *) malloc(size);
    memcpy(mesh->m_vertices, vertices, size);

    mesh->m_enabled = GL_TRUE;
}

void jade_mesh_set_normals (jade_mesh_t *mesh, GLfloat *normals, int size) {

    FREEANDNULL(mesh->m_normals);
    mesh->m_normals = (GLfloat *) malloc(size);
    memcpy(mesh->m_normals, normals, size);
}

void jade_mesh_set_uvs (jade_mesh_t *mesh, GLfloat *uvs, int size) {

    FREEANDNULL(mesh->m_uvs);
    mesh->m_uvs = (GLfloat *) malloc(size);
    memcpy(mesh->m_uvs, uvs, size);
}

void jade_mesh_set_colors (jade_mesh_t *mesh, GLubyte *colors, int size) {

    FREEANDNULL(mesh->m_colors);
    mesh->m_colors = (GLubyte *) malloc(size);
    memcpy(mesh->m_colors, colors, size);
}

void 
jade_mesh_set_indices (jade_mesh_t *mesh, GLshort *indices, int size) {

    FREEANDNULL(mesh->m_indices);
    mesh->m_indices = (GLshort *) malloc(size);
    memcpy(mesh->m_indices, indices, size);
}



void jade_mesh_set_texture_id (jade_mesh_t *mesh, GLint textureId) {

    mesh->m_textureId = textureId;

    return;

}

void jade_mesh_set_position (jade_mesh_t *mesh, GLfloat x, GLfloat y, GLfloat z) {


    LOGD ("jade_mesh_set_position: x = %f, y = %f, z = %f.\n", x, y, z);

    if (mesh->m_position == NULL) {
        mesh->m_position = (GLfloat *) malloc(3 * sizeof(GLfloat));
    }       

    mesh->m_position[0] = x;
    mesh->m_position[1] = y;
    mesh->m_position[2] = z;

    return;
}


void jade_mesh_set_rotate(jade_mesh_t *mesh, GLfloat x, GLfloat y, GLfloat z) {

    if (mesh->m_rotate == NULL) {
        mesh->m_rotate = (GLfloat *) malloc(3 * sizeof(GLfloat));
    }

    mesh->m_rotate[0] = x;
    mesh->m_rotate[1] = y;
    mesh->m_rotate[2] = z;
/*

    m_rotate[0] = a;
    m_rotate[1] = b;
    m_rotate[2] = c;
*/

/*
    m_rotate[0] = 10.0f;
    m_rotate[1] = 10.0f;
    m_rotate[2] = 10.0f;
*/


    //LOGD("m_rotate[0] = %f, r[1] = %f, r[2] = %f.\n", mesh->m_rotate[0], mesh->m_rotate[1], mesh->m_rotate[2]);
}

void jade_mesh_set_scale (jade_mesh_t *mesh, GLfloat x, GLfloat y, GLfloat z) {
    if (mesh->m_scale == NULL) {
        mesh->m_scale = (GLfloat *) malloc(3 * sizeof(GLfloat));
    }

    mesh->m_scale[0] = x;
    mesh->m_scale[1] = y;
    mesh->m_scale[2] = z;
}

void jade_mesh_set_translate (jade_mesh_t *mesh, GLfloat x, GLfloat y, GLfloat z) {
    if (mesh->m_scale == NULL) {
        mesh->m_scale = (GLfloat *) malloc(3 * sizeof(GLfloat));
    }

    mesh->m_scale[0] = x;
    mesh->m_scale[1] = y;
    mesh->m_scale[2] = z;
}



void jade_mesh_set_texture_offset(jade_mesh_t *mesh, GLfloat x, GLfloat y, GLfloat z) {


    LOGD("jade_mesh_set_texture_offset: x = %f, y = %f, z = %f.\n", x, y, z);

    if (mesh->m_texureoffset == NULL) {
        mesh->m_texureoffset = (GLfloat *) malloc(3 * sizeof(GLfloat));
    }

    mesh->m_texureoffset[0] = x;
    //m_texureoffset[1] = -0.25;
    mesh->m_texureoffset[1] = y;
    mesh->m_texureoffset[2] = z;

    LOGD("m_textureoffset[0] = %f, t[1] = %f, t[2] = %f.\n", 
            mesh->m_texureoffset[0], mesh->m_texureoffset[1], mesh->m_texureoffset[2]);
}


static void init_glcmds (jade_mesh_t *mesh) {

    if (mesh->m_vertices != NULL)
        glEnableClientState(GL_VERTEX_ARRAY);

    if (mesh->m_normals != NULL)
        glEnableClientState(GL_NORMAL_ARRAY);

    if (mesh->m_uvs != NULL) {
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        glEnable(GL_TEXTURE_2D);
    } else {
        glDisable(GL_TEXTURE_2D);
    }
if (mesh->m_colors != NULL)
        glEnableClientState(GL_COLOR_ARRAY);
}




void jade_mesh_render (jade_mesh_t *mesh) {

    if (!mesh->m_enabled)
        return;

///    prepare_frame ();


    //save current matrix
    glPushMatrix();

    //enable or disable gl command status
    init_glcmds(mesh);

    if (mesh->m_position != NULL) {
        glTranslatef(mesh->m_position[0], mesh->m_position[1], mesh->m_position[2]);
    }

    if (mesh->m_rotate != NULL) {

        
        //LOGD("m_rotate[0] = %f, r[1] = %f, r[2] = %f.\n", m_rotate[0], m_rotate[1], m_rotate[2]);

        //ratate x axis
        if (mesh->m_rotate[0] != 0.0f)
            glRotatef(mesh->m_rotate[0], 1.0f, 0.0f, 0.0f);
        //ratate y axis
        if (mesh->m_rotate[1] != 0.0f)
            glRotatef(mesh->m_rotate[1], 0.0f, 1.0f, 0.0f);
        //ratate z axis
        if (mesh->m_rotate[2] != 0.0f)
            glRotatef(mesh->m_rotate[2], 0.0f, 0.0f, 1.0f);


        //glRotatef(30.0f, 0.0f, 1.0f, 0.0f);
    }

    if (mesh->m_scale != NULL)
        glScalef(mesh->m_scale[0], mesh->m_scale[1], mesh->m_scale[2]);


    /* Begin: Add for moving texture */
    if (mesh->m_texureoffset != NULL) {

        glMatrixMode(GL_TEXTURE);
        glPushMatrix();
        glLoadIdentity();

        if (mesh->m_texureoffset[0] != 0.0f)
            glTranslatef(mesh->m_texureoffset[0], 0.0f, 0.0f);

        if (mesh->m_texureoffset[1] != 0.0f)
            glTranslatef(0.0f, mesh->m_texureoffset[1], 0.0f);

        if (mesh->m_texureoffset[2] != 0.0f)
            glTranslatef(0.0f, 0.0f, mesh->m_texureoffset[2]);

    }
    /* End: Add for moving texture */


    if (mesh->m_vertices != NULL) {
        glVertexPointer(3, GL_FLOAT, 0, mesh->m_vertices);
    }
    else {
#ifdef DEBUG
        LOGD("No vertices, exit render!\n");
#endif
        return;
    }

    if (mesh->m_normals != NULL)
        glNormalPointer(GL_FLOAT, 0, mesh->m_normals);

    if (mesh->m_uvs != NULL && mesh->m_textureId != -1) {
        glBindTexture(GL_TEXTURE_2D, mesh->m_textureId);
        glTexCoordPointer(2, GL_FLOAT, 0, mesh->m_uvs);
    } else {
        glDisable(GL_TEXTURE_2D);
        if ((mesh->m_uvs != NULL && mesh->m_textureId == -1) ||
                (mesh->m_uvs == NULL && mesh->m_textureId != -1) ) {
#ifdef DEBUG
            //LOGD("Only have uvs or texture id!\n");
#endif
        }
    }

    if (mesh->m_colors != NULL)
        glColorPointer(4, GL_UNSIGNED_BYTE, 0, mesh->m_colors);

    if (mesh->m_indices != NULL) {
        glDrawElements(GL_TRIANGLES, mesh->m_triangleNums * 3, GL_UNSIGNED_SHORT, mesh->m_indices);
    }
    else {
        glDrawArrays(GL_TRIANGLES, 0, mesh->m_triangleNums * 3);
    }

    //restore matrix
    glPopMatrix();


}


